use super::{
    err, err_value, json, ok, plc::Plc, throw_err, Base, Client, ECode, MapSv, Resp, SvCache,
    VBase, VMap, Value,
};
use tracing::{instrument, warn};

pub struct Iter;

impl Base for Iter {}

impl Iter {
    pub async fn do_cmd(&self, para: &Value, cmd: &str, cfg: SvCache, client: &Client) -> Resp {
        let data = para.ckobj()?;

        match cmd {
            "wplc" => self.do_wplc(data, cfg, client).await,
            _ => throw_err!(ECode::NoServe, "no iter serve"),
        }
    }

    #[instrument(skip_all, name = "do_wplc")]
    async fn do_wplc(&self, data: &MapSv, cfg: SvCache, client: &Client) -> Resp {
        warn!(target: "参数", "{:?}", data);

        let plc_id = data.ck_str("uid")?;
        let k = data.ck_str("k")?;
        let t = data.ck_str("t")?;
        let v = data.ck_val("v")?;

        let plc = cfg
            .get(plc_id)
            .ok_or(err_value(ECode::Para, "no plc: {plc_id}"))?;
        let plc = plc.ckobj()?;

        let mut it = MapSv::new();

        it.insert("tp".to_string(), json!("call"));
        it.insert("wplc".to_string(), json!(true));
        it.insert(
            "w".to_string(),
            json!([{
                "k": k,
                "t": t,
                "v": [v],
            }]),
        );

        let plc = Plc::new(&it, plc, &client)?;

        let _ = plc.connect().await?;

        let change = MapSv::new();
        let _ = plc.wplc(&change).await?;

        ok!()
    }
}

impl Iter {
    pub async fn do_get(&self, cmd: &str, cfg: SvCache) -> Resp {
        match cmd {
            "getplc" => self.do_get_plc(cfg).await,
            _ => throw_err!(ECode::NoServe, "no iter get serve"),
        }
    }

    #[instrument(skip_all, name = "get_plc")]
    async fn do_get_plc(&self, cfg: SvCache) -> Resp {
        let iter = cfg
            .get("plc")
            .ok_or(err_value(ECode::Para, "no it cache"))?;
        let iter = iter.ckarray()?;

        let mut ret = Vec::new();

        for cache_id in iter.iter() {
            let cache_id = cache_id.ckstr()?;

            if let Some(it) = cfg.get(cache_id) {
                let it = it.ckobj()?;

                ret.push(json!({
                    "uid": it.ck_str("uid")?,
                    "name": it.ck_str("name")?,
                    "type": it.ck_str("type")?,
                }));
            }
        }

        ok!(ret)
    }
}
